package sybrevolutions



object forvalues {
  
  object throughinheritance {
  
  trait Spineableself[A]{
    def toValSpine:ValSpine[A]
  }//how will you handle base cases? impossible, we need external decoration
  
  trait Spineable[T] extends Function1[T,TypeMan[T]]
  
}
  /*
   * Infrastructure
   */
  
  
  //contains function concrete => structural for datatype
  //specific for each datatype
  trait TypeMan[A]{  //kind: *=>*
    def toValSpine(a:A):ValSpine[A]
    //def toTypeSpines:List[TypeSpine[A]]
  }
  
  //generic view of constructor application to values
  
  //contains function structural => concrete for datatype: structural info is enough to to this
  sealed trait ValSpine[+A] { //stages in constructing a value
    def buildFromSpine:A
  }
  type ConstrDesc = {val n:String}
  case class ConstrExt[A](a:A,desc:ConstrDesc) extends ValSpine[A] {
    def buildFromSpine = a
  }
  case class Apped[A,B](constred: ValSpine[A=>B] , a_ :Typed[A]) extends ValSpine[B] {
    def buildFromSpine = constred.buildFromSpine (a_._1)
  }
  
  
  def Ty [A](a:A)(implicit at: TypeMan[A]):Typed[A] = Typed(a,at)
  case class Typed[A](value:A,typerep:TypeMan[A]) extends Tuple2[A,  TypeMan[A]](value,typerep)
  

  
  
  
  
  
  

  /*
   * Example Typemans
   */
  
  
  class PrimitiveTypeMan[T](name:String) extends TypeMan[T]{
    def toValSpine(a:T):ValSpine[T] = ConstrExt(a, new {val n = a.toString})//throw new Exception("not supposed to take valSpine of a "+name+": handle as primitive")
  }

  //need either manual instance or provided through reflection for every datatype
  implicit object StringMan extends PrimitiveTypeMan[String]("String")
  implicit object CharMan extends TypeMan[Char] {
    def toValSpine(c:Char)= ConstrExt(c, new {val n=c.toString})
  }
  implicit object IntMan extends TypeMan[Int] {
    def toValSpine(i:Int)=ConstrExt(i, new {val n=i.toString})
  }
  case class Tuple2Man[A,B](implicit aman: TypeMan[A], bman: TypeMan[B]) extends TypeMan[Tuple2[A,B]] {
    def toValSpine(p:Tuple2[A,B]) = {val constrf = ConstrExt( (a:A)=>(b:B)=>Tuple2(a,b) , new {val n="Tuple2"})
                                  val awrap = Ty(p._1)
                                  val bwrap = Ty(p._2)
                                  Apped(Apped( constrf
                                             , awrap)
                                       , bwrap)
    }
  }
  case class ListMan[A]()(implicit val view: TypeMan[A] ) extends TypeMan[List[A]] { //self:TypeMan[List[A]] =>
    def toValSpine(l:List[A]):ValSpine[List[A] ] = l match {
      case Nil => ConstrExt[List[A]](Nil, new {val n="Nil"})
      case hd::tl => { val constrf :ValSpine[A=>(List[A]=>List[A])]= ConstrExt[A=>List[A]=>List[A]]( (a:A)=>(as:List[A])=> as, new {val n="List.::"});
                       val hdwrap : Typed[A] = Ty(hd) 
                       val tlwrap = Ty(tl)(ListMan()) //Typed(tl,new ListV()(view))
                       val hdappled :Apped[A, List[A]=>List[A]]  = Apped( constrf,hdwrap)
                       val fullappled:ValSpine[List[A]]         = Apped[List[A],List[A]]     ( hdappled, tlwrap)
                       fullappled
                       Apped     ( Apped( constrf
                                         , hdwrap)
                                 , tlwrap)
                     }
    }
  }
  implicit def List2TypeMan[A](a:A )(implicit view: TypeMan[A]):TypeMan[List[A]] = new ListMan()
  
  

  
  
}

